using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace SymbolicComputation
{
    public class TransformSets
    {
        public static Dictionary<SyntaxKind, List<Transform>> ArrangeTransformsBySyntaxKindOfRoot(Transform[] inTransforms)
        {
            Dictionary<SyntaxKind, List<Transform>> dictionary = new Dictionary<SyntaxKind, List<Transform>>();
            Int32 L;
            List<Transform> transformSet;
            for (L=0;L<inTransforms.Length ;L++)
            {
                if (dictionary.ContainsKey(inTransforms[L].matchToMe.Kind)==false)
                {
                    dictionary.Add(inTransforms[L].matchToMe.Kind, new List<Transform>());
                }
                transformSet = dictionary[inTransforms[L].matchToMe.Kind];
                transformSet.Add(inTransforms[L]);
            }
            return dictionary;
        }

        public static List<Transform> AllAsTransforms()
        {
            return Functional.Maps.Map(AllAsList(), Transform.StringToTransform);
        }

        public static List<String> AllAsList()
        {
            List<String> lOut = new List<String>();
            lOut.AddRange(TransformLists.Commutative());
            lOut.AddRange(TransformLists.Distributive());
            lOut.AddRange(TransformLists.Elementary());
            lOut.AddRange(TransformLists.SimplifyingAlgebraic());
            lOut.AddRange(TransformLists.Exponential());
            //lOut.AddRange(TransformLists.Trigonometric());
            //lOut.AddRange(TransformStrings.Derivatives());
            return lOut;
        }

        public static List<String> AllAsSets()
        {
            List<String> lOut = new List<String>();
            lOut.Add(TransformTexts.Commutative());
            lOut.Add(TransformTexts.Distributive());
            lOut.Add(TransformTexts.Elementary());
            lOut.Add(TransformTexts.SimplifyingAlgebraic());
            lOut.Add(TransformTexts.Exponential());
            //lOut.Add(TransformTexts.Trigonometric());
            //lOut.Add(TransformTexts.Derivatives());
            return lOut;
        }

        public static List<String> TextToStrings(String inText)
        {
            return Miscellaneous.Split(inText, Environment.NewLine);
        }
    }

    public class TransformLists
    {
        public static List<String> Commutative()
        {
            List<String> lOut = new List<string>();
            lOut.Add("a+b~b+a");
            lOut.Add("a+b+c~a+c+b");
            lOut.Add("a-b~-b+a");
            lOut.Add("a*b~b*a");
            lOut.Add("a*b*c~a*c*b");
            lOut.Add("a==b~b==a");
            return lOut;
        }

        public static List<String> Distributive()
        {
            List<String> lOut = new List<string>();
            lOut.Add("a*(b+c)~(a*b+a*c)");
            lOut.Add("a*b+a*c~a*(b+c)");
            lOut.Add("a/c+b/c~(a+b)/c");
            lOut.Add("(a+b)/c~(a/c+b/c)");
            return lOut;
        }

        public static List<String> Elementary()
        {
            List<String> lOut = new List<string>();
            lOut.Add("a*b==c~a==c/b");
            lOut.Add("a+b==c~a==c-b)");
            lOut.Add("a-b==c~a==c+b");
            lOut.Add("a/b==c~a==c*b");
            lOut.Add("-a==b~a==-b");
            lOut.Add("a*b==a*c~b==c");
            lOut.Add("a+b==a+c~b==c");
            lOut.Add("b-a==c-a~b==c");
            lOut.Add("b/a==c/a~b==c");
            lOut.Add("a-b==a-c~b==c");
            lOut.Add("a/b==a/c~b==c");
            lOut.Add("-a==b~a==-b");
            lOut.Add("a/b==c~b==a/c");
            return lOut;
        }

        public static List<String> SimplifyingAlgebraic()
        {
            List<String> lOut = new List<string>();
            lOut.Add("a-a~0");
            lOut.Add("a/a~1");
            lOut.Add("a+0~a");
            lOut.Add("a*1~a");
            lOut.Add("a*0~0");
            lOut.Add("(a)+b~a+b");
            lOut.Add("(a)-b~a-b");
            lOut.Add("(a)*b~a*b");
            lOut.Add("(a)/b~a/b");
            lOut.Add("(a)==b~a==b");
            lOut.Add("a-(-b)~a+b");
            lOut.Add("a+(-b)~a-b");
            lOut.Add("a*(-b)~a*-b");
            lOut.Add("a/(-b)~a/-b");
            lOut.Add("((a))~(a)");
            lOut.Add("-a*-b~a*b");
            lOut.Add("(-a)*b~-a*b");
            //lOut.Add("(a)~a");
            return lOut;
        }

        public static List<String> Exponential()
        {
            List<String> lOut = new List<string>();
            lOut.Add("Math.Pow((Math.Pow(x,m)),n)~Math.Pow(x,(m*n))");
            lOut.Add("Math.Pow(x,1)~x");
            lOut.Add("Math.Pow(x,0)~1");
            lOut.Add("Math.Pow(x,(-1))~1/x");
            lOut.Add("Math.Pow(x,m)*Math.Pow(x,n)~Math.Pow(x,(m+n))");
            lOut.Add("Math.Pow(x,m)/Math.Pow(x,n)~Math.Pow(x,(m-n))");
            lOut.Add("Math.Pow((x*y),n)~Math.Pow(x,n)*Math.Pow(y,n)");
            lOut.Add("Math.Pow((x/y),n)~Math.Pow(x,n)/Math.Pow(y,n)");
            lOut.Add("Math.Pow(x,(-n))~1/Math.Pow(x,n)");
            lOut.Add("Math.Pow((a+b),2)~Math.Pow(a,2)+2*a*b+Math.Pow(2,2)");
            lOut.Add("Math.Pow((a-b),2)~Math.Pow(a,2)-2*a*b+Math.Pow(2,2)");
            lOut.Add("Math.Pow(b,y)==x~y==Math.Log(x,b)");
            lOut.Add("Math.Log(x,b)==y~Math.Pow(b,y)==x");
            lOut.Add("Math.Pow(x,y)==a~x==Math.Pow(a,1/y)");
            return lOut;
        }

        //public static List<String> Trigonometric()
        //{
        //    List<String> lOut = new List<string>();
        //    lOut.Add("Math.Sin(fx)==fy~fx==Math.Asin(fy)");
        //    lOut.Add("Math.Cos(fx)==fy~fx==Math.Acos(fy)");
        //    lOut.Add("Math.Tan(fx)==fy~fx==Math.Atan(fy)");
        //    lOut.Add("Math.Asin(fx)==fy~fx==Math.Sin(fy)");
        //    lOut.Add("Math.Acos(fx)==fy~fx==Math.Cos(fy)");
        //    lOut.Add("Math.Atan(fx)==fy~fx==Math.Tan(fy)");
        //    lOut.Add("Math.Sin(x)/Math.Cos(x)~Math.Tan(x)");
        //    lOut.Add("Math.Sin(Math.Asin(x))~x");
        //    lOut.Add("Math.Cos(Math.Acos(x))~x");
        //    lOut.Add("Math.Tan(Math.Atan(x))~x");
        //    lOut.Add("Math.Pow(Math.Sin(x),2)+Math.Pow(Math.Cos(x),2)~1");
        //    return lOut;
        //}

        //public static List<String> Derivatives()
        //{
        //    List<String> lOut = new List<string>();
        //    lOut.Add("d(x^k)/d(x)~k*x^(k-1)");
        //    lOut.Add("d(u+v)/d(x)~d(u)/d(x)+d(v)/d(x)");
        //    lOut.Add("d(c*u)/d(x)~c*d(u)/d(x)");
        //    lOut.Add("d(u*v)/d(x)~u*d(v)/d(x)+v*d(u)/d(x)");
        //    lOut.Add("d(u/v)/d(x)~(v*d(u)/d(x)-u*d(v)/d(x))/v^2");
        //    lOut.Add("d(Pow(u,k))/d(x)~k*Pow(u,(k-1))*d(u)/d(x)");
        //    return lOut;
        //}
    }

    public class TransformTexts
    {
        public static String Commutative()
        {
            return Miscellaneous.Join(TransformLists.Commutative(), Environment.NewLine);
        }

        public static String Distributive()
        {
            return Miscellaneous.Join(TransformLists.Distributive(), Environment.NewLine);
        }

        public static String Elementary()
        {
            return Miscellaneous.Join(TransformLists.Elementary(), Environment.NewLine);
        }

        public static String SimplifyingAlgebraic()
        {
            return Miscellaneous.Join(TransformLists.SimplifyingAlgebraic(), Environment.NewLine);
        }

        public static String Exponential()
        {
            return Miscellaneous.Join(TransformLists.Exponential(), Environment.NewLine);
        }

        //public static String Trigonometric()
        //{
        //    return Miscellaneous.Join(TransformLists.Trigonometric(), Environment.NewLine);
        //}

        //public static String Derivatives()
        //{
        //    return Miscellaneous.Join(TransformLists.Derivatives(), Environment.NewLine);
        //}
    }
}